package yb.ecp.fast.infra.web;

import io.netty.util.internal.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;

import java.net.URLEncoder;

@Slf4j
@RestController
@RefreshScope
@RequestMapping("/oauth")
public class OauthController {

    @Value("${oauth2.client_id:1}")
    private String clientId;
    @Value("${oauth2.client_secret:1}")
    private String clientSecret;
    @Autowired
    private RestTemplate restTemplate;

    @Value("${restTemplate.url:x}")
    private String url;
    @Value("${gateway.main-url:/}")
    private String mainUrl;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @ResponseBody
    @PostMapping("/api/gate/oauth/login")
    public Mono<Object> login(@RequestParam("code") String code, @RequestParam("redirectUri") String redirectUri) {
        return Mono.fromSupplier(() -> {
            Object tokenInfo = getToken(code, redirectUri);
            return tokenInfo;
        }).subscribeOn(Schedulers.boundedElastic());
    }

//    @RequestMapping(value = "loginByCode", method = RequestMethod.GET)
//    public void loginByCode(HttpServletRequest req, HttpServletResponse resp) throws Exception {
//
//        String code = req.getParameter("code");
//        String redirect_uri = req.getParameter("redirect_uri");
//
//        System.out.println(code);
//        System.out.println(redirect_uri);
//
//        try {
//            Object tokenInfo = getToken(code, redirect_uri);
//
//            if (!(tokenInfo instanceof ResponseEntity)) {
//                LogHelper.error(ErrorCode.Failure.getDesc(), ErrorCode.Failure.getCode());
//                return;
//            }
//            Object resultBody = ((ResponseEntity) tokenInfo).getBody();
//            if (!(resultBody instanceof LinkedHashMap)) {
//                LogHelper.error(ErrorCode.Failure.getDesc(), ErrorCode.Failure.getCode());
//                return;
//            }
//            Object value = ((LinkedHashMap) resultBody).get("access_token");
//            if (value == null) {
//                LogHelper.error(ErrorCode.Failure.getDesc(), ErrorCode.Failure.getCode());
//                return;
//            }
//            Object result = getUserInfo((String) value);
//            Object refreshToken = ((LinkedHashMap) resultBody).get("refresh_token");
//            long time = Long.valueOf((Integer) ((LinkedHashMap) resultBody).get("expires_in"));
//            if (result == null || !(result instanceof LinkedHashMap)) {
//                LogHelper.error(ErrorCode.Failure.getDesc(), ErrorCode.Failure.getCode());
//                return;
//            }
//            Object resultCode = ((LinkedHashMap) result).get("code");
//            if (ErrorCode.Success.getCode() != (int) resultCode) {
//                LogHelper.error(ErrorCode.Failure.getDesc(), ErrorCode.Failure.getCode());
//                return;
//            }
//            Object detailValue = ((LinkedHashMap) result).get("value");
//            if (detailValue == null || !(detailValue instanceof LinkedHashMap)) {
//                LogHelper.error(ErrorCode.Failure.getDesc(), ErrorCode.Failure.getCode());
//                return;
//            }
//            Object principal = ((LinkedHashMap) detailValue).get("principal");
//            if (principal == null || !(principal instanceof LinkedHashMap)) {
//                LogHelper.error(ErrorCode.Failure.getDesc(), ErrorCode.Failure.getCode());
//                return;
//            }
//            Object id = ((LinkedHashMap) principal).get("id");
//            setSession(req, (String) id, (String) value, (String) refreshToken, time);
//
//            LogHelper.debug("code:" + code);
//            if (StringUtil.isNullOrEmpty(redirect_uri)) {
//                resp.sendRedirect(mainUrl);
//                return;
//            }
//            resp.sendRedirect(redirect_uri);
//        } catch (Exception e) {
//            LogHelper.error(e.getMessage(), ErrorCode.Failure.getCode());
//            throw e;
//        }
//
//    }
//
//    private void setSession(HttpServletRequest request, String userId, String accessToken, String refreshToken, long time) {
//        HttpSession httpSession = request.getSession();
//        if (StringUtil.isNullOrSpace(userId) == false) {
//            httpSession.setAttribute("uid", userId);
//            httpSession.setAttribute("accessToken", accessToken);
//            httpSession.setAttribute("refreshToken", refreshToken);
//            redisTemplate.opsForValue().set("accessToken", accessToken, time, TimeUnit.SECONDS);
//        }
//    }

    private Object getToken(String code, String redirect_uri) {
        StringBuffer tokenUrlBuffer = new StringBuffer(url);
        log.info("mainUrl:" + mainUrl);
        tokenUrlBuffer.append("/oauth/token?grant_type=authorization_code&client_id=").append(clientId).append("&client_secret=")
                .append(clientSecret).append("&code=").append(code);
        if (!StringUtil.isNullOrEmpty(redirect_uri)) {
            tokenUrlBuffer.append("&redirect_uri=").append(mainUrl).append("/oauth/loginByCode?redirect_uri=").append(URLEncoder.encode(redirect_uri));
        }
        System.out.println("token_url:" + tokenUrlBuffer);
        log.info("token_url:" + tokenUrlBuffer);
        Object result = restTemplate.postForEntity(tokenUrlBuffer.toString(), null, Object.class);
        log.info("result:" + result);
        return result;
    }

    private Object getUserInfo(String accessToken) {
        StringBuffer userUrlBuffer = new StringBuffer(url);
        userUrlBuffer.append("/oauth/user-me?").append("access_token=").append(accessToken);
        log.info("user_url:" + userUrlBuffer);
        Object userObject = restTemplate.getForObject(userUrlBuffer.toString(), Object.class);
        log.info("user:" + userObject);
        return userObject;
    }

    private Object refresh(String refreshToken) {
        Object result = restTemplate.postForEntity(url + "/oauth/token?grant_type=refresh_token&client_id=" + clientId + "&client_secret=" + clientSecret + "&refresh_token=" + refreshToken, null, Object.class);
        return result;
    }

//    @RequestMapping(value = "logOut", method = RequestMethod.GET)
//    public ActionResult logOut(HttpServletRequest request) {
//        HttpSession httpSession = request.getSession();
//        httpSession.invalidate();
//        return new ActionResult(ErrorCode.Success.getCode(), ErrorCode.Success.getDesc());
//    }
}
